﻿#region Using
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
#endregion Using

namespace LloydGame
{
    public class GameSpotLight : GameLight
    {
        #region Class Fields
        protected Vector3 m_direction;
        protected Vector3 m_orriginalDirection;

        protected float m_cutoffStart;
        protected float m_cutoffEnd;
        protected float m_cutoffExp;

        protected float m_animAngleX = 0.0f;
        protected float m_animAngleZ = 0.0f;
        protected float m_spinSpeed;

        protected ColorAnimation m_colorAnim;
        #endregion Class Fields

        #region Properties
        public Vector3 direction
        {
            get
            {
                return m_direction;
            }
        }

        public float cutoffEnd
        {
            get
            {
                return m_cutoffEnd;
            }
        }
        #endregion Properties

        // constructor
        public GameSpotLight(Game p_game, Vector3 p_position, float p_falloffStart, float p_falloffEnd, Vector3 p_color
            , Vector3 p_direction, float p_cutoffStart, float p_cutoffEnd, float p_cutoffExp, int p_shadowMapSize)
            : base(p_game, p_position, p_falloffStart, p_falloffEnd, p_color, p_shadowMapSize)
        {
            p_direction.Normalize();
            m_direction = p_direction;
            m_orriginalDirection = m_direction;

            m_cutoffStart = (float)Math.Cos(MathHelper.ToRadians(p_cutoffStart));
            m_cutoffEnd = (float)Math.Cos(MathHelper.ToRadians(p_cutoffEnd));
            m_cutoffExp = p_cutoffExp;

            if (p_shadowMapSize > 0)
            {
                m_shadowMap = new SpotLightShadowMap(p_game, p_shadowMapSize);
            }

            m_animAngleX = (float)((Game1)Game).random.NextDouble();
            m_animAngleZ = (float)((Game1)Game).random.NextDouble();
            m_spinSpeed = (float)((Game1)Game).random.NextDouble() * 0.5f + 0.5f;

            m_colorAnim = new ColorAnimation();
        }

        // move the light according to the gameobject it is attached to
        protected override void moveLight()
        {
            base.moveLight();

            Matrix rot = Matrix.CreateFromYawPitchRoll(
                m_attachedTo.rotation.Y,
                m_attachedTo.rotation.X,
                m_attachedTo.rotation.Z);

            m_direction = Vector3.Transform(m_orriginalDirection, rot);
        }

        protected override void animateLight(GameTime p_gameTime)
        {
            float secs = p_gameTime.ElapsedRealTime.Milliseconds / 1000.0f;

            m_animAngleX += m_spinSpeed * (float)Math.PI * secs / 3.0f;
            m_animAngleZ += m_spinSpeed * (float)Math.PI * secs / 3.0f;

            Vector2 rotate = new Vector2((float)Math.Sin(m_animAngleX), (float)Math.Cos(m_animAngleX));
            rotate.Normalize();

            m_direction = new Vector3(rotate.X, -2, rotate.Y);
            m_direction.Normalize();

            m_createStaticShadowMap = true;

            m_colorAnim.update(p_gameTime);
            m_color = m_colorAnim.color;
        }

        // update light parameters
        public override void UpdateLight(EffectParameter p_effectParameter, Matrix p_world)
        {
            base.UpdateLight(p_effectParameter, p_world);

            p_effectParameter.StructureMembers["direction"].SetValue(new Vector4(m_direction, 0));
            p_effectParameter.StructureMembers["cutoffStart"].SetValue(m_cutoffStart);
            p_effectParameter.StructureMembers["cutoffEnd"].SetValue(m_cutoffEnd);
            p_effectParameter.StructureMembers["cutoffExp"].SetValue(m_cutoffExp);

            if (m_shadowMap != null)
            {
                p_effectParameter.StructureMembers["wvp"].SetValue(p_world * ((SpotLightShadowMap)m_shadowMap).viewProj);
            }
        }
    }
}
